package com.liuqi.openai.model.input;

import com.github.mustachejava.DefaultMustacheFactory;
import com.github.mustachejava.Mustache;
import com.github.mustachejava.MustacheFactory;
import java.io.StringReader;
import java.io.StringWriter;
import java.time.Clock;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

import static com.liuqi.openai.util.ValidationUtil.ensureNotBlank;

/**
 * 用于解析文本的模板
 *
 * 模板通常包含一个或多个定义为{{variable_name}}的变量(占位符)，它们是替换为实际值以产生提示
 *
 * 特殊变量{{current_date}}, {{current_time}},{{current_date_time}}分别用LocalDate.now()、LocalTime.now()和LocalDateTime.now()填充
 *
 * 这个类使用Mustache模板引擎，所以所有的Mustache语法和特性都被支持。
 *
 * @author liuqi
 * @date 2025/7/19
 **/
public class PromptTemplate {

    private final MustacheTemplate template;
    private final Clock clock;

    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    public PromptTemplate(String template) {
        this(template, Clock.systemDefaultZone());
    }

    PromptTemplate(String template, Clock clock) {
        this.template = new MustacheTemplate(ensureNotBlank(template, "template"));
        this.clock = clock;
    }

    public Prompt parse(Map<String, Object> variables) {
        return new Prompt(template.render(injectDateTimeVariables(variables)));
    }

    private Map<String, Object> injectDateTimeVariables(Map<String, Object> variables) {
        Map<String, Object> variablesCopy = new HashMap<>(variables);
        variablesCopy.put("current_date", LocalDate.now(clock).toString());
        variablesCopy.put("current_time", LocalTime.now(clock).toString());
        variablesCopy.put("current_date_time", LocalDateTime.now(clock).format(formatter));
        return variablesCopy;
    }

    public static PromptTemplate from(String template) {
        return new PromptTemplate(template);
    }

    private static class MustacheTemplate {
        static final MustacheFactory MUSTACHE_FACTORY = new DefaultMustacheFactory();
        final String template;
        final String name;
        final Mustache mustache;
        MustacheTemplate(String template) {
            this(template, "template");
        }
        MustacheTemplate(String template, String name) {
            this.template = template;
            this.name = name;
            this.mustache = MUSTACHE_FACTORY.compile(new StringReader(template), name);
        }
        String render(Map<String, Object> vars) {
            StringWriter writer = new StringWriter();
            mustache.execute(writer, vars);
            return writer.toString();
        }
    }

}
